package org.com.lcuiot.security;

import io.jsonwebtoken.*;
import org.com.lcuiot.common.LcuConst;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Base64;
import java.util.Collection;
import java.util.Date;

import static java.util.stream.Collectors.joining;

/**
 * JWT令牌生成验证逻辑
 *
 * @author gaoge
 * @since 2022/10/27 15:29
 */
@Component
public class JwtTokenProvider {

    private static final String AUTHORITIES_KEY = "roles";
    /**
     * 密钥盐
     */
    @Value("${jwt.secret}")
    private String secret;

    /**
     * 过期时间 毫秒
     */
    @Value("${jwt.expiration}")
    private Long expiration;

    /**
     * 密钥key
     */
    private String secretKey;


    @PostConstruct
    public void init() {
        secretKey = Base64.getEncoder().encodeToString(secret.getBytes());
    }

    public String createToken(Authentication authentication) {
        JwtUser jwtUser = (JwtUser) authentication.getPrincipal();
        String username = authentication.getName();
        Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();

        Claims claims = Jwts.claims().setSubject(LcuConst.LCU_IOT_QST);
        if (!authorities.isEmpty()) {
            claims.put(AUTHORITIES_KEY, authorities.stream().map(GrantedAuthority::getAuthority).collect(joining(",")));
        }
        claims.put(LcuConst.USERNAME, username);
        claims.put(LcuConst.ORGANIZATION_ID, jwtUser.getOrganizationId());
        claims.put(LcuConst.NAME, jwtUser.getName());

        Date now = new Date();
        Date validity = new Date(now.getTime() + expiration);

        return Jwts.builder()
                .setClaims(claims)
                .setIssuedAt(now)
                .setExpiration(validity)
                .signWith(SignatureAlgorithm.HS256, this.secretKey)
                .compact();

    }

    public Authentication getAuthentication(String token) {
        Claims claims = Jwts.parser().setSigningKey(this.secretKey).parseClaimsJws(token).getBody();

        Object authoritiesClaim = claims.get(AUTHORITIES_KEY);

        Collection<? extends GrantedAuthority> authorities = authoritiesClaim == null ? AuthorityUtils.NO_AUTHORITIES
                : AuthorityUtils.commaSeparatedStringToAuthorityList(authoritiesClaim.toString());

        JwtUser principal = new JwtUser((String) claims.get(LcuConst.USERNAME), "", Long.valueOf(claims.get(LcuConst.ORGANIZATION_ID).toString()), (String) claims.get(LcuConst.NAME));

        return new UsernamePasswordAuthenticationToken(principal, token, authorities);
    }

    public boolean validateToken(String token) {
        try {
            Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);

            if (claims.getBody().getExpiration().before(new Date())) {
                return false;
            }

            return true;
        } catch (Exception e) {
            return false;
        }

    }

}
